#include "SmtpSSL.h"

#include "root_certificates/root_certificates.h"

#include <iostream>
#include <ostream>


namespace smtp {
    bool SmtpSSL::verify_certificate(bool preverified, ssl::verify_context& ctx) {
        char subject_name[256];
        X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
        X509_NAME_oneline(X509_get_subject_name(cert), subject_name, sizeof(subject_name));
        std::cout << "Verifying: " << subject_name << std::endl;
        return preverified;
    }
    SmtpSSL::SmtpSSL(std::string host, std::string port)
        : ioc(),
          ctx(ssl::context::tls_client),
          //   ctx(ssl::context::tlsv12_client),
          stream(ioc, ctx) {
        boost::system::error_code error_code = boost::asio::error::host_not_found;
        // This holds the root certificate used for verification
        // load_root_certificates(ctx);
        ctx.set_default_verify_paths();  // 使用系统默认的根证书路径

        // Verify the remote server's certificate
        ctx.set_verify_mode(ssl::verify_peer);
        ctx.set_verify_callback([this](bool preverified, ssl::verify_context& ctx) {
            return this->verify_certificate(preverified, ctx);
        });

        // These objects perform our I/O
        tcp::resolver resolver(ioc);

        // Set SNI Hostname (many hosts need this to handshake successfully)
        if (!SSL_set_tlsext_host_name(stream.native_handle(), host.c_str())) {
            boost::system::error_code ec{static_cast<int>(::ERR_get_error()), net::error::get_ssl_category()};
            throw boost::system::system_error{ec};
        }

        // Look up the domain name
        auto const results = resolver.resolve(host, port);

        // Make the connection on the IP address we get from a lookup
        // beast::get_lowest_layer(stream).connect(results);
        // stream.get_lowest_layer().connect(results);
        stream.lowest_layer().connect(*results.begin(), error_code);

        if (error_code) {
            throw boost::system::system_error{error_code};
        }

        // Perform the SSL handshake
        stream.handshake(ssl::stream_base::client, error_code);
        if (error_code) {
            throw boost::system::system_error{error_code};
        }
    }

    SmtpSSL::~SmtpSSL() {
    }
    void SmtpSSL::run() {
        ioc.run();
    }
    void SmtpSSL::send(const std::string& msg) {
        SmtpBase::send(stream, msg);
    }
    std::string SmtpSSL::get_response() {
        return SmtpBase::get_response(stream);
    }
}  // namespace smtp